package nl.unimaas.micc.eventSnookerTest.simulation.event;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import nl.unimaas.micc.eventSnookerTest.domain.BilliardBall;
import nl.unimaas.micc.eventSnookerTest.domain.Cushion;
import nl.unimaas.micc.eventSnookerTest.domain.Ball.BallState;
import nl.unimaas.micc.eventSnookerTest.domain.Cushion.Orientations;
import nl.unimaas.micc.eventSnookerTest.math.BairstowSolver;
import nl.unimaas.micc.eventSnookerTest.math.Transformation3D;
import nl.unimaas.micc.eventSnookerTest.math.Vector3D;
import nl.unimaas.micc.eventSnookerTest.math.XYRotationTrans3D;
import nl.unimaas.micc.eventSnookerTest.simulation.physics.BallMotion;
import nl.unimaas.micc.eventSnookerTest.simulation.physics.Physics;

public class CushionCollision extends Event {

	private BilliardBall ball;
	private Orientations cushionOrientation;
	private static Cushion north = new Cushion(0,1,Orientations.NORTH);
	private static Cushion south = new Cushion(0,0.1,Orientations.SOUTH);
	private static Cushion east = new Cushion(1,0,Orientations.EAST);
	private static Cushion west = new Cushion(0.1,0,Orientations.WEST);
	
	public CushionCollision(double time, Set<BilliardBall> ball, Orientations orientation) {
		super(time, ball);
		System.out.println("New Cushion Collision at "+ time);
		// TODO Auto-generated constructor stub
		this.ball = (BilliardBall) ball.toArray()[0] ;
		this.cushionOrientation = orientation;
	}

	@Override
	public void handle() {
		System.out.println("Orientation: " + cushionOrientation);
		BallMotion motion = ball.getState().getMotion();
		Vector3D av = motion.getAngularVelocity(ball, getTime());
		Vector3D p = motion.getPosition(ball, getTime());
		//System.out.println("Old State: " + ball.getState());
		ball.setVelocity(ball.getState().getMotion().getVelocity(ball, getTime()));
		ball.setTime(getTime());
		ball.setAngularVelocity(av);
		ball.setPosition(p);
		ball.setState(BallState.SLIDING);
		//System.out.println("New state: " + ball.getState());
		Vector3D velocity = ball.getVelocity();
		System.out.println("Old Velocity: " + velocity);
		
		
		if(cushionOrientation == Orientations.NORTH || cushionOrientation == Orientations.SOUTH){
			velocity.y = -velocity.y;
			if(cushionOrientation == Orientations.NORTH){
				p.y = p.y - 0.0001;
				ball.setPosition(p);
			}
			else{
				p.y = p.y + 0.0001;
				ball.setPosition(p);
			}
		}
		else{
			velocity.x = -velocity.x;
			if(cushionOrientation == Orientations.EAST){
				p.x = p.x - 0.0001;
				ball.setPosition(p);
			}
			else{
				p.x = p.x + 0.0001;
				ball.setPosition(p);
			}
			
		}
		System.out.println("New velocity: " + velocity);
	}

	public static CushionCollision find(BilliardBall ball){
		double[] times = {north.getCollisionTime(ball),south.getCollisionTime(ball),
				east.getCollisionTime(ball),west.getCollisionTime(ball)};
		double minTime = Double.MAX_VALUE;
		int index = 0;
		for(int i = 0; i < times.length; i++){
			if(times[i] > 0 && times[i] < minTime){
				minTime = times[i];
				index = i;			
			}
		}

		Orientations orientation = Orientations.NORTH; 
		switch(index){
		case 0: orientation = Orientations.NORTH; break;
		case 1: orientation = Orientations.SOUTH; break;
		case 2: orientation = Orientations.EAST; break;
		case 3: orientation = Orientations.WEST; break;
		}
		
		return new CushionCollision(ball.getTime()+minTime,toSet(ball),orientation);

	}
	
	private static Set<BilliardBall> toSet(BilliardBall ball)
	{
		HashSet<BilliardBall> h = new HashSet<BilliardBall>();
		h.add(ball);
		return h;
	}
	
}
